#include "I2C.h"

static void I2C_Start(void);
static void I2C_Stop(void);
static void I2C_WriteByte(char Byte);
static I2CAckStatus I2C_WaitACK(void);
static short I2C_ReadByte(void);
static void I2C_ACK(void);
static void I2C_NACK(void);
static void delay_us(int us);

I2CStatus I2C_WriteReg(INT8U Reg , INT8U Data)
{
    INT8U write;
    
    I2C_Start();
    
    I2C_WriteByte(I2C_WRITE);
    if(I2C_WaitACK() == NACK)
    {
    }
   
    write = Reg;
    I2C_WriteByte(write);
    if(I2C_WaitACK() == NACK)
    {
    }

    write = Data;
    I2C_WriteByte(write);
    if(I2C_WaitACK() == NACK)
    {
    }
    
    I2C_Stop();

    return WriteOK;
}

I2CStatus I2C_WriteContinuity(INT8U Reg , INT8U *Data, INT8U Len)
{
    INT8U write;
    INT8U ii;
    
    I2C_Start();
    
    I2C_WriteByte(I2C_WRITE);
    if(I2C_WaitACK() == NACK)
    {
    }
   
    write = Reg;
    I2C_WriteByte(write);
    if(I2C_WaitACK() == NACK)
    {
    }

    for(ii = 0 ; ii <Len ; ii++)
    {
        write = Data[ii];
        I2C_WriteByte(write);
        if(I2C_WaitACK() == NACK)
        {
        }        
    }
    
    I2C_Stop();

    return WriteOK;
}

INT8U I2C_ReadReg(INT8U Reg)
{
    INT8U write;
    INT8U read;
    
    I2C_Start();
    
    I2C_WriteByte(I2C_WRITE);
    
    if(I2C_WaitACK() == NACK)
    {
    }
    
    write = Reg;
    I2C_WriteByte(write);
    if(I2C_WaitACK() == NACK)
    {
    }

    I2C_Stop();
    I2C_Start();
    
    I2C_WriteByte(I2C_READ);
    if(I2C_WaitACK() == NACK)
    {
    }
    
    read = I2C_ReadByte();//1001 1000 //0011 1100
    I2C_NACK();
    
    I2C_Stop();
    return read;
}

static void I2C_Start(void)
{
    SDA_OUT();
    SDA_HIGH();
    SCK_HIGH();
    delay_us(1);
    SDA_LOW();
    delay_us(1);
    SCK_LOW();
}

static void I2C_Stop(void)
{
    SDA_OUT();
    SCK_LOW();
    SDA_LOW();
    delay_us(1);
    SCK_HIGH();
    delay_us(1);
    SDA_HIGH();
    delay_us(1);
}

static void I2C_WriteByte(char Byte)
{
    char ii;
    
    SDA_OUT();

    for(ii = 0 ; ii < 8 ; ii++)
    {
        SCK_LOW();
        
        if(Byte & 0x80)
        {
            SDA_HIGH();
            delay_us(1);
            SCK_HIGH();
            delay_us(1);
        }
        else
        {
            SDA_LOW();
            delay_us(1);
            SCK_HIGH();    
            delay_us(1);          
        }
        Byte<<=1;
    }
    SCK_LOW();    
}

static short I2C_ReadByte(void)
{
    char ii;
    char data = 0;
    
    SDA_IN();
    
    for(ii = 0 ; ii < 8 ; ii++)
    {
        SCK_LOW();
        delay_us(1);
        SCK_HIGH();
        if(SDA_READ())
        {
            data |= 0x01;
        }
        else
        {
            data &= 0xfe;
        }
        if(ii < 7)
        {
            data<<=1;
        }
        delay_us(1);
    }
    return data;
}

static I2CAckStatus I2C_WaitACK(void)
{
    int Err;
    
    delay_us(1);
    SDA_HIGH();    
    SDA_IN();
    delay_us(1);
    SCK_HIGH();
    delay_us(1);
    while(SDA_READ())
    {
        Err++;
        if(Err>125)
        {
            return NACK;
        }
    }
    SCK_LOW();
    return ACK;
}

static void I2C_ACK(void)
{
	SCK_LOW();
	SDA_OUT();
    delay_us(1);
	SDA_LOW();
	delay_us(1);
    SCK_HIGH();
    delay_us(1);
    SCK_LOW();
}

static void I2C_NACK(void)
{
	SCK_LOW();
	SDA_OUT();
    delay_us(1);
	SDA_HIGH();
	delay_us(1);
    SCK_HIGH();
    delay_us(1);
    SCK_LOW();   
}

static void delay_us(int us)
{
    int32_t ii;
    
    for(ii = 0 ; ii < (5*us) ; ii++)
    {
        __NOP();
    }
}

void I2C_Test(void)
{
    I2C_WriteReg(0x01,0x01);
    HAL_DelayMS(50);
}
